package aos2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.PriorityBlockingQueue;

public class MyTailServer extends MyServer {
	private int id;
	private Client client;
	private int logicalClock;
	private List<ServerRequest> localReqHistory;
	private Hashtable<String, Integer> neighborServers = new Hashtable<String, Integer>();
	private int seqnum;
	private static final int offset = 4;
	private HashMap<String, MyVector> map = new HashMap<String, MyVector>();
	private PriorityBlockingQueue<MyVector> queue = new PriorityBlockingQueue<MyVector>();

	public MyTailServer(String configFile) {
		super(configFile);
		client = new Client();
	}

	@Override
	protected void handleRequest(Socket skt) {
		try {
			InputStream is = skt.getInputStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(is));
			OutputStream os = skt.getOutputStream();
			PrintWriter pw = new PrintWriter(os, true);
			//TODO InetSocketAddress clientAddress = new InetSocketAddress("localhost", 5000);
			String incoming = null;
			while ((incoming = br.readLine()) != null) {
				String response = null;
				Request req = parseRequest(incoming);
				switch (req.getType()) {
				case CLIENT_READ:
					break;
				case CLIENT_WRITE:
					synchronized (this) {
						logicalClock += offset;
						seqnum++;
					}
					ServerRequest curReq = new ServerRequest();
					curReq.setFileName(req.getFileName());
					curReq.setMessage(req.getMessage());
					curReq.setSeqNum(seqnum);
					curReq.setTimeStamp(logicalClock);
					curReq.setType(RequestType.SERVER_WRITE);
					curReq.setRequestorId(id);

					localReqHistory.add(curReq);
					for (Entry<String, Integer> es : neighborServers.entrySet()) {
						client.makeRequest(es.getKey(), es.getValue(), curReq);
					}

					break;
				case TAILSERVER_WRITE:
					TailServerRequest tsreq = parseTailServerRequest(incoming);
					String key = tsreq.getRequestorId() + "-"
							+ tsreq.getSeqNum();// this forms a unique key
				/*	if (!map.containsKey(key)) {
						System.out.println("Map dont have key");
						MyVector myv = new MyVector();
						myv.id = tsreq.getRequestorId();
						myv.vector[myv.id - 1] = tsreq.getTimeStamp();
						myv.vector[tsreq.getForwarderId() - 1] = tsreq
								.getForwarderTimeStamp();
						map.put(key, myv);
					} else {
						System.out.println("map have key");
						MyVector myv = map.get(key);
						myv.key = key;
						myv.vector[tsreq.getForwarderId() - 1] = tsreq
								.getForwarderTimeStamp();
						int flag = 1;
						for (int i : myv.vector) {
							flag *= i;
						}
						if (flag != 0) {
							queue.add(myv);
						}
					}*/
					pw.println("Bye.");
					System.out.println("The request reached here-"
							+ tsreq.getMessage());
					if (queue.size() > 3) {
						synchronized(this){
						response = queue.poll().key;
						Request r = new Request();
						r.setMessage(response);
						r.setType(RequestType.TAILSERVER_WRITE_RESPONSE);
						client.makeRequest("localhost", 5002, r);
						map.remove(response);
						}
					}
					break;
				case SERVER_READ:
					break;
				}

			}

			//pw.println("Bye.");
			pw.close();
			os.close();
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	private TailServerRequest parseTailServerRequest(String msg) {
		TailServerRequest tsreq = new TailServerRequest();
		String[] temp = msg.split(":");
		if (temp[0].endsWith("WRITE")) {
			tsreq.setType(RequestType.TAILSERVER_WRITE);
		} else {
			tsreq.setType(RequestType.TAILSERVER_READ);
		}
		tsreq.setFileName(temp[1]);
		tsreq.setMessage(temp[2]);
		tsreq.setTimeStamp(Integer.parseInt(temp[3]));
		tsreq.setSeqNum(Integer.parseInt(temp[4]));
		tsreq.setRequestorId(Integer.parseInt(temp[5]));
		tsreq.setForwarderId(Integer.parseInt(temp[6]));
		tsreq.setForwarderTimeStamp(Integer.parseInt(temp[7]));
		return tsreq;
	}

	public static void main(String[] args) {
		MyTailServer tserv = new MyTailServer("config.properties");
		tserv.startServer();
	}
}

/*class MyVector implements Comparable<MyVector> {
	int[] vector;
	int id;
	boolean isready = false;
	String key;

	public MyVector() {
		vector = new int[3];
	}

	@Override
	public int compareTo(MyVector arg0) {
		boolean sm_or_eq = true;
		boolean lg_or_eq = true;
		for (int i = 0; i < vector.length; i++) {
			sm_or_eq = sm_or_eq && (vector[i] <= arg0.vector[i]);
			if (!sm_or_eq)
				break;
		}
		if (sm_or_eq) {
			for (int i = 0; i < vector.length; i++) {
				if (vector[i] < arg0.vector[i])
					return -1;
			}
		} else {
			for (int i = 0; i < vector.length; i++) {
				lg_or_eq = lg_or_eq && (vector[i] >= arg0.vector[i]);
				if (!lg_or_eq)
					break;
			}
		}
		if (lg_or_eq) {
			for (int i = 0; i < vector.length; i++) {
				if (vector[i] > arg0.vector[i])
					return 1;
			}
		}

		if (id < arg0.id) {
			return -1;
		} else {
			return 1;
		}
	}
}*/